﻿using ChronoScript_Compiler.Language;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Viper.Opcodes;

namespace ChronoScript_Compiler.CodeGen
{
    public partial class CodeGen
    {
        public void GetIntegerValue(LanguageDefinition.SyntaxNode sn)
        {
            if (sn is LanguageDefinition.IntLiteral)
            {
                Assembler.Emit(new push_d((uint)((LanguageDefinition.IntLiteral)sn).value));
            }
            else if (sn is LanguageDefinition.FunctionCall)
            {
                LanguageDefinition.FunctionCall fc = sn as LanguageDefinition.FunctionCall;
                if (GetReturnType(fc) != "int")
                    Errors.Add("Method " + fc.Target + " does not return type int!");
                else
                    Call(fc);
            }
            else if (sn is LanguageDefinition.Expression)
            {
                ParseArthemeticExpression(sn as LanguageDefinition.Expression);
            }
        }

        public void ParseArthemeticExpression(LanguageDefinition.Expression exp)
        {
            foreach (LanguageDefinition.SyntaxNode sn in exp.Items)
            {
                if (sn is LanguageDefinition.Operator)
                {
                    LanguageDefinition.Operator op = sn as LanguageDefinition.Operator;
                    GetIntegerValue(op.Op1);
                    GetIntegerValue(op.Op2);
                    if (sn is LanguageDefinition.Plus)
                        Assembler.Emit(new Add());
                    else if (sn is LanguageDefinition.Multiply)
                        Assembler.Emit(new mul_s());
                    else if (sn is LanguageDefinition.Subtract)
                        Assembler.Emit(new sub());
                    else if (sn is LanguageDefinition.Divide)
                        Assembler.Emit(new div_s());
                    else if (sn is LanguageDefinition.LeftBitshift)
                        Assembler.Emit(new shl());
                    else if (sn is LanguageDefinition.RightBitshift)
                        Assembler.Emit(new shr());
                    else
                        Errors.Add("Operator '" + op.theOperator + "' can not be applied between int");
                }
                else
                {
                    GetIntegerValue(sn);
                }
            }
        }

        public void ParseUnsignedArthemeticExpression(LanguageDefinition.Expression exp)
        {
            foreach (LanguageDefinition.SyntaxNode sn in exp.Items)
            {
                if (sn is LanguageDefinition.Operator)
                {
                    LanguageDefinition.Operator op = sn as LanguageDefinition.Operator;
                    GetIntegerValue(op.Op1);
                    GetIntegerValue(op.Op2);
                    if (sn is LanguageDefinition.Plus)
                        Assembler.Emit(new Add());
                    else if (sn is LanguageDefinition.Multiply)
                        Assembler.Emit(new mul());
                    else if (sn is LanguageDefinition.Subtract)
                        Assembler.Emit(new sub());
                    else if (sn is LanguageDefinition.Divide)
                        Assembler.Emit(new div());
                    else if (sn is LanguageDefinition.LeftBitshift)
                        Assembler.Emit(new shl());
                    else if (sn is LanguageDefinition.RightBitshift)
                        Assembler.Emit(new shr());
                    else
                        Errors.Add("Operator '" + op.theOperator + "' can not be applied to type uint");
                }
                else
                {
                    GetIntegerValue(sn);
                }
            }
        }
    }
}
